package io.lkt.modules.sys.service.impl;

import io.lkt.common.utils.DateUtil;
import io.lkt.modules.sys.entity.ButtonEventInfo;
import io.lkt.modules.sys.service.ButtonEventService;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedTopHits;
import org.elasticsearch.search.aggregations.metrics.TopHitsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class ButtonEventServiceImpl implements ButtonEventService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public List<ButtonEventInfo> queryList(int page, int size, String pEventCode, String pGzhCode, String startDate, String endDate,Integer pUserId,Integer pFollowStatus) throws IOException, ParseException {
        // 搜索请求对象
        SearchRequest searchRequest = new SearchRequest("button_event_index");

        // 搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //分页
//        int page = 1; // 页码
//        int size = 20; // 每页显示的条数
        int index = (page - 1) * size;
        searchSourceBuilder.from(index);
        searchSourceBuilder.size(size);
        searchSourceBuilder.sort("createtime", SortOrder.DESC);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        if (pEventCode != null) {
            boolQuery.must(QueryBuilders.matchQuery("eventcode", pEventCode));
        }

        if (pGzhCode != null) {
            boolQuery.must(QueryBuilders.matchQuery("gzhcode", pGzhCode));
        }

        if (pUserId != null) {
            boolQuery.must(QueryBuilders.matchQuery("userid", pUserId));
        }

        if (pFollowStatus != null) {
            boolQuery.must(QueryBuilders.matchQuery("followstatus", pFollowStatus));
        }

        if (startDate != null && endDate != null) {

            // 日期格式化对象
            //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            boolQuery.must(QueryBuilders.rangeQuery("createtime")
                    .from(startDate, true)
                    .to(endDate, true));
        }

        searchSourceBuilder.query(boolQuery);

        // 设置源字段过虑,第一个参数结果集包括哪些字段，第二个参数表示结果集不包括哪些字段
        searchSourceBuilder.fetchSource(new String[]{
                "eventcode", "eventname", "userid", "gzhcode", "createtime", "nickname", "gzhname",
                "followstatus", "followuserid", "followusername", "followtime", "remarks"
        }, new String[]{});
        // 向搜索请求对象中设置搜索源
        searchRequest.source(searchSourceBuilder);
        // 执行搜索,向ES发起http请求
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        // 搜索结果
        SearchHits hits = searchResponse.getHits();
        int k = searchResponse.getHits().getHits().length;
        // 匹配到的总记录数
        TotalHits totalHits = hits.getTotalHits();
        // 得到匹配度高的文档
        SearchHit[] searchHits = hits.getHits();

        int rowIndex = 0;

        List<ButtonEventInfo> buttonEventInfos = null;
        if (searchHits != null && searchHits.length > 0) {
            buttonEventInfos = new ArrayList<>();
            for (SearchHit hit : searchHits) {
                // 文档的主键
                String id = hit.getId();
                // 源文档内容
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                buttonEventInfos.add(buildButtonEventInfo(id,sourceAsMap));
                rowIndex++;
            }
        }
        return buttonEventInfos;
    }

    @Override
    public List<ButtonEventInfo> queryAggregation( String pEventCode, String pGzhCode, String startDate, String endDate,Integer pUserId) throws IOException, ParseException {
        // 搜索请求对象
        SearchRequest searchRequest = new SearchRequest("button_event_index");

        // 搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //分页
//        int page = 1; // 页码
//        int size = 20; // 每页显示的条数
//        int index = (page - 1) * size;
//        searchSourceBuilder.from(index);
//        searchSourceBuilder.size(size);
//        searchSourceBuilder.sort("createtime", SortOrder.DESC);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

//        if (pEventCode != null) {
//            boolQuery.must(QueryBuilders.matchQuery("eventcode", pEventCode));
//        }

        boolQuery.must(QueryBuilders.matchQuery("followstatus", 0));

        if (pEventCode != null) {
            boolQuery.must(QueryBuilders.matchQuery("eventcode", pEventCode));
        }else{
            // .should 是 or ;   .must 是 and ;
            boolQuery.must(QueryBuilders.boolQuery()
                    //.should(QueryBuilders.matchQuery("eventcode", "K0002"))  //点击客户页“我要追踪客户”
                    .should(QueryBuilders.matchQuery("eventcode", "K0003"))  //点击文章库底部“去开通”
                    .should(QueryBuilders.matchQuery("eventcode", "K0006"))  //点击个人中心“开通会员”
                    .should(QueryBuilders.matchQuery("eventcode", "K0011"))//点击“领取红包”
                    .should(QueryBuilders.matchQuery("eventcode", "K0012"))//点击海报上传“去开通”
                    .should(QueryBuilders.matchQuery("eventcode", "K0013"))//点击VIP名片“开通会员”
                    .should(QueryBuilders.matchQuery("eventcode", "K0014"))//邀请按钮设置"去开通"
                    .should(QueryBuilders.matchQuery("eventcode", "K0015"))//公开我的分享内容"去开通"
            );
        }

        if (pGzhCode != null) {
            boolQuery.must(QueryBuilders.matchQuery("gzhcode", pGzhCode));
        }

        if (pUserId != null) {
            boolQuery.must(QueryBuilders.matchQuery("userid", pUserId));
        }

        if (startDate != null && endDate != null) {

            // 日期格式化对象
            //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            boolQuery.must(QueryBuilders.rangeQuery("createtime")
                    .from(startDate, true)
                    .to(endDate, true));
        }

        searchSourceBuilder.query(boolQuery);

        TermsAggregationBuilder teamAgg = AggregationBuilders.terms("userid_count ").field("userid").size(100);
        TermsAggregationBuilder eventCountAgg = AggregationBuilders.terms("event_count").field("eventcode");

        //聚合之后 取其它 字段的值
        TopHitsAggregationBuilder eventNameAgg = AggregationBuilders.topHits("event_name").docValueField("eventname.keyword").size(1).sort("createtime", SortOrder.DESC);;// +".keyword" 是不分词，在这里的作用没有体验出来
        eventCountAgg.subAggregation(eventNameAgg);

//        TopHitsAggregationBuilder nickNameAgg= AggregationBuilders.topHits("nick_name").docValueField("nickname.keyword").size(1);
//        teamAgg.subAggregation(nickNameAgg);
        teamAgg.subAggregation(eventCountAgg);

        searchSourceBuilder.aggregation(teamAgg);


        // 向搜索请求对象中设置搜索源
        searchRequest.source(searchSourceBuilder);
        // 执行搜索,向ES发起http请求
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        List<ButtonEventInfo> buttonEventInfos = new ArrayList<>();
        Aggregations aggregations = searchResponse.getAggregations();
        Aggregation aggregation = aggregations.asList().get(0);

        List<? extends Terms.Bucket> buckets = ((ParsedLongTerms) aggregation).getBuckets();
        for (Terms.Bucket bucket : buckets) {
            System.out.println("userID:" + bucket.getKey() + "__count:" + bucket.getDocCount());
            Aggregation aggregation_event = bucket.getAggregations().getAsMap().get("event_count");

            List<? extends Terms.Bucket> buckets_event = ((ParsedStringTerms) aggregation_event).getBuckets();
            for (Terms.Bucket bucket_e : buckets_event) {

                Aggregation aggregation_eventName = bucket_e.getAggregations().getAsMap().get("event_name");
                SearchHits searchHits = ((ParsedTopHits) aggregation_eventName).getHits();
//                String nickname = searchHits.getHits()[0].getSourceAsMap().get("nickname").toString();
//                String eventname = searchHits.getHits()[0].getSourceAsMap().get("eventname").toString();


                ButtonEventInfo be=buildButtonEventInfo(searchHits.getHits()[0].getId(),searchHits.getHits()[0].getSourceAsMap());
                be.setClickCount(bucket_e.getDocCount());

                System.out.println("--eventCode:" + be.getEventcode() + "__count:" + be.getClickCount()
                        + "__nickName:" + be.getUserName()
                        + "__eventName:" + be.getEventname()
                        + "__id:" + searchHits.getHits()[0].getId()
                );

                buttonEventInfos.add(be);
            }
        }

        return buttonEventInfos;
    }

    @Override
    public List<ButtonEventInfo> queryList2(int page, int size, String pEventCode, String pGzhCode, String startDate, String endDate,Integer pUserId) throws IOException, ParseException {
        // 搜索请求对象
        SearchRequest searchRequest = new SearchRequest("button_event_index");

        // 搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //分页
//        int page = 1; // 页码
//        int size = 20; // 每页显示的条数
        int index = (page - 1) * size;
        searchSourceBuilder.from(index);
        searchSourceBuilder.size(size);
        searchSourceBuilder.sort("createtime", SortOrder.DESC);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        if (pEventCode != null) {
            boolQuery.must(QueryBuilders.matchQuery("eventcode", pEventCode));
        }else{
            // .should 是 or ;   .must 是 and ;
            boolQuery.must(QueryBuilders.boolQuery()
                    //.should(QueryBuilders.matchQuery("eventcode", "K0002"))  //点击客户页“我要追踪客户”
                    .should(QueryBuilders.matchQuery("eventcode", "K0003"))  //点击文章库底部“去开通”
                    .should(QueryBuilders.matchQuery("eventcode", "K0006"))  //点击个人中心“开通会员”
                    .should(QueryBuilders.matchQuery("eventcode", "K0011"))//点击“领取红包”
                    .should(QueryBuilders.matchQuery("eventcode", "K0012"))//点击海报上传“去开通”
                    .should(QueryBuilders.matchQuery("eventcode", "K0013"))//点击VIP名片“开通会员”
                    .should(QueryBuilders.matchQuery("eventcode", "K0014"))//邀请按钮设置"去开通"
                    .should(QueryBuilders.matchQuery("eventcode", "K0015"))//公开我的分享内容"去开通"
            );
        }

        if (pGzhCode != null) {
            boolQuery.must(QueryBuilders.matchQuery("gzhcode", pGzhCode));
        }

        if (pUserId != null) {
            boolQuery.must(QueryBuilders.matchQuery("userid", pUserId));
        }


        if (startDate != null && endDate != null) {

            // 日期格式化对象
            //SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            boolQuery.must(QueryBuilders.rangeQuery("createtime")
                    .from(startDate, true)
                    .to(endDate, true));
        }

        searchSourceBuilder.query(boolQuery);

        // 设置源字段过虑,第一个参数结果集包括哪些字段，第二个参数表示结果集不包括哪些字段
        searchSourceBuilder.fetchSource(new String[]{
                "eventcode", "eventname", "userid", "gzhcode", "createtime", "nickname", "gzhname",
                "followstatus", "followuserid", "followusername", "followtime", "remarks"
        }, new String[]{});
        // 向搜索请求对象中设置搜索源
        searchRequest.source(searchSourceBuilder);
        // 执行搜索,向ES发起http请求
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        // 搜索结果
        SearchHits hits = searchResponse.getHits();
        int k = searchResponse.getHits().getHits().length;
        // 匹配到的总记录数
        TotalHits totalHits = hits.getTotalHits();
        // 得到匹配度高的文档
        SearchHit[] searchHits = hits.getHits();

        int rowIndex = 0;

        List<ButtonEventInfo> buttonEventInfos = null;
        if (searchHits != null && searchHits.length > 0) {
            buttonEventInfos = new ArrayList<>();
            for (SearchHit hit : searchHits) {
                // 文档的主键
                String id = hit.getId();
                // 源文档内容
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                buttonEventInfos.add(buildButtonEventInfo(id,sourceAsMap));
                rowIndex++;
            }
        }
        return buttonEventInfos;
    }

    @Override
    public int updateByIdSingle(ButtonEventInfo buttonEventInfo) throws IOException {
        return updateById(buttonEventInfo);
    }

    private int updateById(ButtonEventInfo buttonEventInfo) throws IOException {
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.index("button_event_index")
                .id(buttonEventInfo.getId())
                .doc(XContentFactory.jsonBuilder()
                        .startObject()
                        .field("followstatus", buttonEventInfo.getFollowstatus())
                        .field("followuserid", buttonEventInfo.getFollowuserid())
                        .field("followusername", buttonEventInfo.getFollowusername())
                        .field("followtime", DateUtil.getFormatDate("yyyy-MM-dd HH:mm:ss", new Date()))
                        .field("remarks", buttonEventInfo.getRemarks())
                        .endObject()
                );
        //执行修改
        UpdateResponse response1 = client.update(updateRequest, RequestOptions.DEFAULT);
        return response1.status().getStatus();
    }

    @Override
    @Async
    public void batchUpdateById(ButtonEventInfo buttonEventInfo) throws IOException, ParseException {

        int res = 0;
        SearchRequest searchRequest = new SearchRequest("button_event_index");

        // 搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.size(1000);
        searchSourceBuilder.sort("createtime", SortOrder.DESC);

        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //boolQuery.must(QueryBuilders.matchQuery("eventcode", buttonEventInfo.getEventcode()));
        boolQuery.must(QueryBuilders.matchQuery("gzhcode", buttonEventInfo.getGzhcode()));
        boolQuery.must(QueryBuilders.matchQuery("userid", buttonEventInfo.getUserid()));
        boolQuery.must(QueryBuilders.matchQuery("followstatus", 0));

        searchSourceBuilder.query(boolQuery);

        // 设置源字段过虑,第一个参数结果集包括哪些字段，第二个参数表示结果集不包括哪些字段
        searchSourceBuilder.fetchSource(new String[]{
                "eventcode", "eventname", "userid", "gzhcode", "createtime", "nickname", "gzhname","followstatus"}, new String[]{});
        // 向搜索请求对象中设置搜索源
        searchRequest.source(searchSourceBuilder);
        // 执行搜索,向ES发起http请求
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        // 搜索结果
        SearchHits hits = searchResponse.getHits();
        int k = searchResponse.getHits().getHits().length;
        // 匹配到的总记录数
        TotalHits totalHits = hits.getTotalHits();
        // 得到匹配度高的文档
        SearchHit[] searchHits = hits.getHits();

        if (searchHits != null && searchHits.length > 0) {
            for (SearchHit hit : searchHits) {

                ButtonEventInfo be = new ButtonEventInfo();

                // 文档的主键
                be.setId(hit.getId());
                be.setFollowstatus(buttonEventInfo.getFollowstatus());
                be.setFollowuserid(buttonEventInfo.getFollowuserid());
                be.setFollowusername(buttonEventInfo.getFollowusername());
                be.setRemarks(buttonEventInfo.getRemarks()+"(批处理)");

                updateById(be);
                res++;
            }
        }
    }

    @Override
    public ButtonEventInfo getInfoById(String id) throws IOException, ParseException {

        GetRequest getRequest = new GetRequest("button_event_index", id);

        // 执行搜索,向ES发起http请求
        GetResponse searchResponse = client.get(getRequest, RequestOptions.DEFAULT);

        ButtonEventInfo be=  buildButtonEventInfo(id, searchResponse.getSourceAsMap());

        return be;
    }

    private ButtonEventInfo buildButtonEventInfo(String id, Map<String, Object> sourceAsMap) {

        String nickname = "";
        String gzhname = "";
        Integer followstatus = 0;
        Integer followuserid = 0;
        String followusername = "";
        String followtime = "";
        String remarks = "";

        // 源文档内容
        String eventcode = (String) sourceAsMap.get("eventcode");
        // 由于前边设置了源文档字段过虑，这时description是取不到的
        String eventname = (String) sourceAsMap.get("eventname");

        Integer userid = (Integer) sourceAsMap.get("userid");
        String gzhcode = (String) sourceAsMap.get("gzhcode");
        // 日期
        String createtime = (String) sourceAsMap.get("createtime");

        if (sourceAsMap.get("nickname") != null) {
            nickname = (String) sourceAsMap.get("nickname");
        }

        if (sourceAsMap.get("gzhname") != null) {
            gzhname = (String) sourceAsMap.get("gzhname");
        }

        if (sourceAsMap.get("followstatus") != null) {
            followstatus = (Integer) sourceAsMap.get("followstatus");
        }

        if (sourceAsMap.get("followuserid") != null) {
            followuserid = (Integer) sourceAsMap.get("followuserid");
        }

        if (sourceAsMap.get("followusername") != null) {
            followusername = (String) sourceAsMap.get("followusername");
        }

        if (sourceAsMap.get("followtime") != null) {
            followtime = (String) sourceAsMap.get("followtime");
        }

        if (sourceAsMap.get("remarks") != null) {
            remarks = (String) sourceAsMap.get("remarks");
        }

        ButtonEventInfo be = new ButtonEventInfo();
        be.setId(id);
        be.setEventcode(eventcode);
        be.setEventname(eventname);
        be.setUserid(userid);
        be.setUserName(nickname);
        be.setGzhcode(gzhcode);
        be.setGzhName(gzhname);
        be.setCreatetime(createtime);
        be.setFollowstatus(followstatus);
        be.setFollowuserid(followuserid);
        be.setFollowusername(followusername);
        be.setFollowtime(followtime);
        be.setRemarks(remarks);

        return be;
    }
}
